using System;
using System.Collections.Generic;
using System.Text;
using Xeml.Document;
using Xeml.Document.Contracts;
using Mpi.Common.Collections;

namespace Xeml.Sampling
{
    public class SampleColumn : Column
    {
        private string expName;
        private SamplePropertyTarget target;

        internal SamplePropertyTarget Target
        {
            get { return target; }
            set { target = value; }
        }


        public string ExperimentName
        {
            get { return expName; }
            set { expName = value; }
        }

        public override object ExtractRowValue(object extract)
        {
            //if (this.target == SamplePropertyTarget.ReplicaGroup && !(extract is ObservationPoint))
            //    throw new ArgumentException("Argument type is not ObservationPoint while targrt is set to ReplicaGroup.");
            if (!(extract is Sample))
                throw new ArgumentException("Argument type is not Sample");

            Sample s = extract as Sample;

            if (target == SamplePropertyTarget.ExperimentName)
                return this.expName;
            if (target == SamplePropertyTarget.Id)
                return s.Id;

            if (target == SamplePropertyTarget.Time)
                return s.TimePoint;

            if (target == SamplePropertyTarget.RealTime)
            {
                StoryBase sb = s.Collection.Story;
                IDocument doc = sb.StoryBoard.Owner;


                return doc.StartDate.Add(s.TimePoint);
            }

            if (target == SamplePropertyTarget.StoryLabel)
                return (s.Collection.Story).Label;

            if (target == SamplePropertyTarget.GermPlasm)
                return ExtractGermPlasm(s);

            if (target == SamplePropertyTarget.Material)
                return ExtractMaterial(s);

            if (target == SamplePropertyTarget.DevelopmentalStage)
                return ExtractDevelopmentalStage(s);

            if (target == SamplePropertyTarget.IndividualCount)
                return ExtractIndividualCount(s);

            if (target == SamplePropertyTarget.Individuals)
                return ExtractIndividuals(s);

            if (target == SamplePropertyTarget.ReplicaGroup)
                return ExtractReplicaGroup(s);

            return "-";
        }



        private object ExtractReplicaGroup(Sample s)
        {
            return s.GetHashCode();


            StoryBase sb = s.Collection.Story;
            StoryBoard sbo = sb.StoryBoard;
            SortedDictionary<int, Sample> sdict = new SortedDictionary<int, Sample>();
            Dictionary<int, int> rdict = new Dictionary<int, int>();
            Dictionary<int, int> hashdict = new Dictionary<int, int>();
            foreach (TreeNode<StoryBase> item in sbo)
            {
                foreach (var sample in item.Content.Samples)
                {
                    sdict.Add(sample.Id, sample);
                    hashdict.Add(sample.Id, sample.GetHashCode());
                }
            }

            int replgroup = 0;

            //Sample lastSample = null;

            int sampleHash = hashdict[s.Id];

            foreach (var item in sdict.Keys)
            {
                if (!rdict.ContainsKey(hashdict[item]))
                {
                    replgroup++;
                    rdict.Add(hashdict[item], replgroup);
                }
                if (hashdict.ContainsKey(sampleHash))
                    return hashdict[sampleHash];

            }

            return -1;
        }

        private bool SamplesAreEqual(Sample sample, Sample sample_2)
        {
            StoryBase sb1 = sample.Collection.Story;
            StoryBase sb2 = sample_2.Collection.Story;

            if (sb1 != sb2)
                return false;
            if (sample.TimePoint != sample_2.TimePoint)
                return false;
            if (sample.Partitions.Count != sample_2.Partitions.Count)
                return false;
            foreach (var item in sample.Partitions)
            {
                if (!FindEqualPartition(item, sample_2.Partitions))
                    return false;
            }

            List<string> germplasmList1 = new List<string>();
            foreach (var item in sample.Partitions)
            {
                Observation o = item.Collection.Observation;
                if (!germplasmList1.Contains(o.IndividualsPool.FqName))
                    germplasmList1.Add(o.IndividualsPool.FqName);
            }

            List<string> germplasmList2 = new List<string>();
            foreach (var item in sample_2.Partitions)
            {
                Observation o = item.Collection.Observation;
                if (!germplasmList2.Contains(o.IndividualsPool.FqName))
                    germplasmList2.Add(o.IndividualsPool.FqName);
            }

            if (germplasmList1.Count != germplasmList1.Count)
                return false;
            foreach (var item in germplasmList1)
            {
                if (!germplasmList2.Contains(item))
                    return false;

            }



            return true;
        }

        private bool FindEqualPartition(Partition item, IEnumerable<Partition> list)
        {
            bool found = true;
            foreach (var part in list)
            {
                found = true;
                foreach (Term mat in part.Material)
                {
                    if (!item.Material.Contains(mat.TermId))
                    {
                        found = false;
                        break;
                    }
                }
                if (found)
                    break;
            }
            return found;
        }

        private object ExtractIndividuals(Sample s)
        {
            List<int> ind = new List<int>();
            foreach (Partition part in s.Partitions)
            {
                Observation ob = part.Collection.Observation;
                if (ob != null)
                {
                    if (ob.Individual == null)
                        ind.Add(42);
                    else if (!ind.Contains(ob.Individual.Id))
                        ind.Add(ob.Individual.Id);
                }
            }
            StringBuilder sb = new StringBuilder();
            foreach (int i in ind)
            {
                sb.AppendFormat("{0}\r\n", i);

            }
            if (sb.Length > 1)
                sb.Remove(sb.Length - 2, 2);
            return sb.ToString();

        }

        private object ExtractIndividualCount(Sample s)
        {

            List<int> ind = new List<int>();
            foreach (Partition part in s.Partitions)
            {
                Observation ob = part.Collection.Observation;
                if (ob != null)
                {
                    if (ob.Individual == null)
                        ind.Add(42);
                    else if (!ind.Contains(ob.Individual.Id))
                        ind.Add(ob.Individual.Id);
                }
            }
            return ind.Count;
        }

        private object ExtractMaterial(Sample s)
        {
            StringBuilder sb = new StringBuilder();
            List<string> material = new List<string>();
            foreach (Partition part in s.Partitions)
            {
                foreach (Term m in part.Material)
                {
                    if (!material.Contains(m.Name))
                        material.Add(m.Name);
                }

            }
            foreach (string m in material)
            {
                sb.AppendFormat("{0},", m);
            }
            if (sb.Length >= 1)
            {
                sb.Remove(sb.Length - 1, 1);
            }
            return sb.ToString();
        }

        private object ExtractDevelopmentalStage(Sample s)
        {
            StringBuilder sb = new StringBuilder();
            List<string> devs = new List<string>();
            foreach (var item in s.Partitions)
            {
                foreach (var dev in item.Collection.Observation.DevelopmentalStages)
                {
                    if (!devs.Contains(dev.Name))
                        devs.Add(dev.Name);
                }
            }
            foreach (string m in devs)
            {
                sb.AppendFormat("{0},", m);
            }
            if (sb.Length >= 1)
            {
                sb.Remove(sb.Length - 1, 1);
            }
            return sb.ToString();
        }

        private string ExtractGermPlasm(Sample s)
        {
            StringBuilder sb = new StringBuilder();
            List<string> plasms = new List<string>();
            foreach (Partition part in s.Partitions)
            {
                Observation ob = part.Collection.Observation;
                if (ob != null)
                {
                    if (!plasms.Contains(ob.IndividualsPool.FqName))
                        plasms.Add(ob.IndividualsPool.FqName);
                }
            }
            foreach (string gp in plasms)
            {
                sb.AppendFormat("{0},", gp);
            }
            if (sb.Length >= 1)
            {
                sb.Remove(sb.Length - 1, 1);
            }
            return sb.ToString();
        }
    }

    internal enum SamplePropertyTarget
    {
        Id,
        Time,
        RealTime,
        ExperimentName,
        StoryLabel,
        GermPlasm,
        Material,
        IndividualCount,
        Individuals,
        ReplicaGroup,
        DevelopmentalStage

    }
}
